"""
铁粉圈下载模块 - 提取的核心下载逻辑
"""

import requests
from bs4 import BeautifulSoup
import re
import os
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
from pathlib import Path
from PySide2.QtCore import QObject, Signal, QThread


class TiefenquanVideoDownloader(QObject):
    """铁粉圈视频下载器类"""

    # 信号定义
    progress_updated = Signal(int)  # 进度更新
    status_updated = Signal(str)  # 状态信息
    download_completed = Signal(bool, str)  # 下载完成
    error_occurred = Signal(str)  # 错误信息

    def __init__(self):
        super().__init__()
        self.headers = {
            "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
            "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
            "cache-control": "max-age=0",
            "priority": "u=0, i",
            "referer": "https://www.tiefenquan1.com/tags/%E9%B1%BC%E7%A5%9E/",
            "sec-ch-ua": "\"Not;A=Brand\";v=\"99\", \"Microsoft Edge\";v=\"139\", \"Chromium\";v=\"139\"",
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": "\"Windows\"",
            "sec-fetch-dest": "document",
            "sec-fetch-mode": "navigate",
            "sec-fetch-site": "same-origin",
            "sec-fetch-user": "?1",
            "upgrade-insecure-requests": "1",
            "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0"
        }
        self.cookies = {"timezone": "8"}
        self.is_downloading = False

    def stop_download(self):
        """停止下载"""
        self.is_downloading = False
        self.status_updated.emit("下载已停止")

    def download_video(self, url, folder_path):
        """主下载方法 - 下载铁粉圈视频"""
        try:
            self.is_downloading = True
            self.status_updated.emit("🌐 开始获取网页内容...")

            response = requests.get(url, headers=self.headers, cookies=self.cookies, timeout=30)

            if response.status_code != 200:
                error_msg = f"❌ 获取网页失败，状态码: {response.status_code}"
                self.status_updated.emit(error_msg)
                self.error_occurred.emit("网页获取失败")
                return False

            self.status_updated.emit("🔍 正在解析页面内容...")
            html_content = response.text

            # 解析页面，查找DPlayer视频链接
            soup = BeautifulSoup(html_content, 'html.parser')
            scripts = soup.find_all('script')

            mp4_url = None
            for script in scripts:
                if 'DPlayer' in script.text and 'url:' in script.text:
                    # 使用正则表达式提取 url 的值
                    match = re.search(r'url:\s*["\']([^"\']+)["\']', script.text)
                    if match:
                        mp4_url = match.group(1)
                        self.status_updated.emit(f"✅ 找到视频链接: {mp4_url}")
                        break

            if not mp4_url:
                error_msg = "❌ 未找到视频链接"
                self.status_updated.emit(error_msg)
                self.error_occurred.emit("未找到视频链接")
                return False

            # 确保保存目录存在
            folder_path = Path(folder_path)
            folder_path.mkdir(parents=True, exist_ok=True)

            # 从URL中提取文件名
            filename = mp4_url.split('/')[-1]
            if not filename.endswith('.mp4'):
                filename += '.mp4'

            # 如果文件名为空或无效，使用时间戳
            if not filename or filename == '.mp4':
                filename = f"tiefenquan_video_{int(time.time())}.mp4"

            filepath = folder_path / filename

            self.status_updated.emit(f"⬇️ 开始下载视频: {filename}")

            # 优先使用多线程下载，如果失败则回退到单线程
            success = self._download_video_multithread(mp4_url, filepath)
            if not success and self.is_downloading:
                self.status_updated.emit("🔄 多线程下载失败，尝试单线程下载...")
                success = self._download_video_with_progress(mp4_url, filepath)

            if success:
                self.status_updated.emit("✅ 视频下载完成!")
                self.download_completed.emit(True, str(filepath))
            else:
                self.error_occurred.emit("视频下载失败")

            return success

        except Exception as e:
            error_msg = f"💥 发生错误: {str(e)}"
            self.status_updated.emit(error_msg)
            self.error_occurred.emit(str(e))
            return False
        finally:
            self.is_downloading = False

    def _download_video_with_progress(self, video_url, filepath):
        """带进度的视频下载 - 优化版本"""
        try:
            if not self.is_downloading:
                return False

            # 优化的请求头，支持断点续传
            headers = self.headers.copy()
            headers.update({
                'Accept-Encoding': 'gzip, deflate',
                'Connection': 'keep-alive',
                'Range': 'bytes=0-'  # 支持范围请求
            })

            # 使用更大的超时时间和优化的session
            session = requests.Session()
            session.headers.update(headers)

            response = session.get(video_url, stream=True, timeout=60)
            response.raise_for_status()

            # 获取文件总大小
            total_size = int(response.headers.get('content-length', 0))
            downloaded_size = 0

            self.status_updated.emit(f"📊 文件大小: {total_size / (1024*1024):.2f} MB")

            # 使用更大的chunk_size来提升下载速度
            chunk_size = 1024 * 1024  # 1MB chunk size，比原来的8KB大很多

            with open(filepath, 'wb') as f:
                for chunk in response.iter_content(chunk_size=chunk_size):
                    if not self.is_downloading:
                        # 如果停止下载，删除不完整的文件
                        if filepath.exists():
                            filepath.unlink()
                        return False

                    if chunk:
                        downloaded_size += len(chunk)
                        f.write(chunk)

                        # 更新进度 - 减少更新频率以提升性能
                        if total_size > 0:
                            progress = int((downloaded_size / total_size) * 100)
                            self.progress_updated.emit(progress)

            # 检查文件是否下载完整
            if filepath.exists() and filepath.stat().st_size > 0:
                actual_size = filepath.stat().st_size
                if total_size > 0 and actual_size != total_size:
                    self.status_updated.emit(f"⚠️ 文件大小不匹配: 期望 {total_size}, 实际 {actual_size}")

                self.status_updated.emit(f"✅ 视频已保存为: {filepath.name}")
                return True
            else:
                self.status_updated.emit("❌ 下载的文件无效")
                if filepath.exists():
                    filepath.unlink()
                return False

        except Exception as e:
            self.status_updated.emit(f"❌ 下载失败: {str(e)}")
            if filepath.exists():
                filepath.unlink()
            return False

    def _download_video_multithread(self, video_url, filepath):
        """多线程分段下载视频 - 更快的下载速度"""
        try:
            if not self.is_downloading:
                return False

            # 首先获取文件信息
            headers = self.headers.copy()
            response = requests.head(video_url, headers=headers, timeout=30)

            # 检查服务器是否支持范围请求
            accept_ranges = response.headers.get('Accept-Ranges', '').lower()
            content_length = response.headers.get('Content-Length')

            if not content_length:
                self.status_updated.emit("⚠️ 无法获取文件大小，使用单线程下载")
                return self._download_video_with_progress(video_url, filepath)

            total_size = int(content_length)
            self.status_updated.emit(f"📊 文件大小: {total_size / (1024*1024):.2f} MB")

            # 如果文件小于10MB或服务器不支持范围请求，使用单线程下载
            if total_size < 10 * 1024 * 1024 or accept_ranges != 'bytes':
                self.status_updated.emit("📥 使用单线程下载模式")
                return self._download_video_with_progress(video_url, filepath)

            # 使用多线程下载
            self.status_updated.emit("🚀 使用多线程下载模式")
            num_threads = min(4, max(2, total_size // (5 * 1024 * 1024)))  # 2-4个线程
            chunk_size = total_size // num_threads

            # 创建临时文件列表
            temp_files = []
            download_tasks = []

            for i in range(num_threads):
                start = i * chunk_size
                end = start + chunk_size - 1 if i < num_threads - 1 else total_size - 1
                temp_file = f"{filepath}.part{i}"
                temp_files.append(temp_file)
                download_tasks.append((video_url, temp_file, start, end, i))

            # 使用线程池下载
            downloaded_parts = [0] * num_threads

            def download_part(args):
                url, temp_file, start, end, part_index = args
                try:
                    headers = self.headers.copy()
                    headers['Range'] = f'bytes={start}-{end}'

                    response = requests.get(url, headers=headers, stream=True, timeout=60)
                    response.raise_for_status()

                    with open(temp_file, 'wb') as f:
                        for chunk in response.iter_content(chunk_size=1024*1024):
                            if not self.is_downloading:
                                return False
                            if chunk:
                                f.write(chunk)
                                downloaded_parts[part_index] += len(chunk)

                                # 更新总进度
                                total_downloaded = sum(downloaded_parts)
                                progress = int((total_downloaded / total_size) * 100)
                                self.progress_updated.emit(progress)

                    return True
                except Exception as e:
                    self.status_updated.emit(f"❌ 分段{part_index}下载失败: {str(e)}")
                    return False

            # 执行多线程下载
            with ThreadPoolExecutor(max_workers=num_threads) as executor:
                futures = [executor.submit(download_part, task) for task in download_tasks]

                # 等待所有下载完成
                all_success = True
                for future in as_completed(futures):
                    if not future.result():
                        all_success = False
                        break

                if not all_success or not self.is_downloading:
                    # 清理临时文件
                    for temp_file in temp_files:
                        if Path(temp_file).exists():
                            Path(temp_file).unlink()
                    return False

            # 合并文件
            self.status_updated.emit("🔄 正在合并文件...")
            with open(filepath, 'wb') as output_file:
                for temp_file in temp_files:
                    if Path(temp_file).exists():
                        with open(temp_file, 'rb') as input_file:
                            output_file.write(input_file.read())
                        Path(temp_file).unlink()  # 删除临时文件

            # 验证文件完整性
            if filepath.exists() and filepath.stat().st_size == total_size:
                self.status_updated.emit(f"✅ 多线程下载完成: {filepath.name}")
                return True
            else:
                self.status_updated.emit("❌ 文件合并失败或不完整")
                if filepath.exists():
                    filepath.unlink()
                return False

        except Exception as e:
            self.status_updated.emit(f"❌ 多线程下载失败: {str(e)}")
            # 清理临时文件
            for i in range(10):  # 最多清理10个临时文件
                temp_file = f"{filepath}.part{i}"
                if Path(temp_file).exists():
                    Path(temp_file).unlink()
            if filepath.exists():
                filepath.unlink()
            return False


class TiefenquanDownloader(QObject):
    """铁粉圈下载器类"""
    
    # 信号定义
    progress_updated = Signal(int)  # 进度更新
    status_updated = Signal(str)  # 状态信息
    download_completed = Signal(bool, str)  # 下载完成
    error_occurred = Signal(str)  # 错误信息
    image_found = Signal(int)  # 发现图片数量
    
    def __init__(self):
        super().__init__()
        self.headers = {
            "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
            "accept-language": "zh-CN,zh;q=0.9,en;q=0.8",
            "accept-encoding": "gzip, deflate, br",
            "cache-control": "max-age=0",
            "connection": "keep-alive",
            "upgrade-insecure-requests": "1",
            "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36"
        }
        self.cookies = {"timezone": "8"}
        self.is_downloading = False

    def stop_download(self):
        """停止下载"""
        self.is_downloading = False
        self.status_updated.emit("下载已停止")

    def download_images(self, url, folder_path):
        """主下载方法"""
        try:
            self.is_downloading = True
            self.status_updated.emit("🌐 开始获取网页内容...")
            
            response = requests.get(url, headers=self.headers, cookies=self.cookies, timeout=30)
            
            if response.status_code != 200:
                error_msg = f"❌ 获取网页失败，状态码: {response.status_code}"
                self.status_updated.emit(error_msg)
                self.error_occurred.emit("网页获取失败")
                return False
            
            soup = BeautifulSoup(response.text, 'html.parser')
            target_div = soup.find('div', class_='post-content tiefenquan', id='lightgallery')
            
            img_srcs = []
            if target_div:
                img_tags = target_div.find_all('img')
                img_srcs = [img['src'] for img in img_tags if img.get('src')]
                self.status_updated.emit(f"🔍 找到 {len(img_srcs)} 张图片")
                self.image_found.emit(len(img_srcs))
            else:
                error_msg = "❌ 未找到目标内容"
                self.status_updated.emit(error_msg)
                self.error_occurred.emit("未找到图片内容")
                return False
            
            # 获取标题作为文件夹名
            title_tag = soup.find('title')
            if title_tag:
                title = title_tag.get_text().strip()
                title = re.sub(r'[\\/*?:"<>|]', "", title)
                title = title[:100]  # 限制长度
            else:
                title = f"下载_{int(time.time())}"
            
            folder_path = Path(folder_path) / title
            folder_path.mkdir(parents=True, exist_ok=True)
            self.status_updated.emit(f"📁 创建文件夹: {folder_path}")
            
            # 开始下载
            self.status_updated.emit("⬇️ 开始下载图片...")
            success = self._download_images_concurrent(img_srcs, folder_path)
            
            if success:
                self.status_updated.emit("✅ 下载完成!")
                self.download_completed.emit(True, str(folder_path))
            else:
                self.error_occurred.emit("下载过程中出现错误")
                
            return success
            
        except Exception as e:
            error_msg = f"💥 发生错误: {str(e)}"
            self.status_updated.emit(error_msg)
            self.error_occurred.emit(str(e))
            return False
        finally:
            self.is_downloading = False

    def _download_images_concurrent(self, img_srcs, folder_path):
        """多线程下载图片"""
        def download_single_image(img_data):
            src, index = img_data
            try:
                if not self.is_downloading:
                    return False, f"下载已取消: image_{index+1:03d}.jpg"
                    
                response = requests.get(src, headers=self.headers, cookies=self.cookies, timeout=30)
                if response.status_code == 200:
                    img_path = folder_path / f"image_{index+1:03d}.jpg"
                    with open(img_path, 'wb') as f:
                        f.write(response.content)
                    return True, f"✓ 已下载: image_{index+1:03d}.jpg"
                else:
                    return False, f"✗ 下载失败 (状态码 {response.status_code}): image_{index+1:03d}.jpg"
            except Exception as e:
                return False, f"💥 下载错误 image_{index+1:03d}.jpg: {str(e)}"
        
        img_data_list = [(src, i) for i, src in enumerate(img_srcs)]
        total_images = len(img_data_list)
        
        success_count = 0
        failed_count = 0
        
        with ThreadPoolExecutor(max_workers=8) as executor:
            future_to_img = {executor.submit(download_single_image, img_data): img_data for img_data in img_data_list}
            
            completed = 0
            for future in as_completed(future_to_img):
                if not self.is_downloading:
                    break
                    
                success, result_msg = future.result()
                self.status_updated.emit(result_msg)
                
                if success:
                    success_count += 1
                else:
                    failed_count += 1
                    
                completed += 1
                progress = int((completed / total_images) * 100)
                self.progress_updated.emit(progress)
        
        return success_count > 0


class TiefenquanVideoDownloadThread(QThread):
    """铁粉圈视频下载线程"""

    def __init__(self, downloader, url, folder_path):
        super().__init__()
        self.downloader = downloader
        self.url = url
        self.folder_path = folder_path

    def run(self):
        """运行视频下载任务"""
        self.downloader.download_video(self.url, self.folder_path)


class TiefenquanDownloadThread(QThread):
    """铁粉圈图片下载线程"""

    def __init__(self, downloader, url, folder_path):
        super().__init__()
        self.downloader = downloader
        self.url = url
        self.folder_path = folder_path

    def run(self):
        """运行图片下载任务"""
        self.downloader.download_images(self.url, self.folder_path)
